using System;
using System.Collections.Generic;
using System.Text;
using Lucene.Net.Search;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Documents;
using Lucene.Net.Analysis;
using FutureOpen.Core.func.analyzer;
using FutureOpen.Core.func.util;
using NHibernate.Connection;
using NHibernate.Driver;
using NHibernate;
using NHibernate.SqlCommand;
using System.Data;
using System.Collections;
using NHibernate.Cfg;


namespace FutureOpen.Core.func.search
{
    public class IndexManager
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private static IndexReader readerArt = null;
        private static IndexWriter writerArt = null;

        private static readonly string pathArt = ConfigUtil.GetArtIndex();

        public static IndexReader GetArtIndexReader()
        {
            if (readerArt == null)
            {
                readerArt = IndexReader.Open(pathArt);
            }
            else
            {
                if (readerArt.GetVersion() < IndexReader.GetCurrentVersion(pathArt))
                {
                    readerArt.Close();
                }
                //RAMDirectory directory = new RAMDirectory(INDEX_PATH);
                readerArt = IndexReader.Open(pathArt);
            }
            return readerArt;
        }

         public static IndexWriter GetArtIndexWriter()
        {
            if (writerArt != null)
            {
                throw new Exception("Index is open, close it first");
            }
            
            writerArt = new IndexWriter(pathArt, new ShootAnalyzer(), false);
            writerArt.SetMaxBufferedDocs(1000);
            writerArt.SetMaxMergeDocs(1000);
            return writerArt;            
            
        }
        public static void CloseIndexWriter()
        {
            if (writerArt != null)
            {
                writerArt.Close();
                writerArt = null;
            }
        }

        
        public static IndexWriter GetUsrIndexWriter()
        {
            return null;
        }


        #region Indexing Process

        

        #endregion
    }

    #region Index Type
    public class IndexStatus
    {
        public static readonly short IndexType_New = 0;
        public static readonly short IndexType_Updated = 1;
        public static readonly short IndexType_Indexed = 2;

    }
    #endregion


    class IndexArt
    {
        protected Configuration config;
        protected ISessionFactory factory;
        protected string CONNSTR = ConfigUtil.GetConnectionStr();
        protected IndexWriter writer = null;
        protected IndexReader reader = null;
        private static readonly string BATCH_SQL = "SELECT * from Art where art_index={1} limit 0,{0}";
        private static readonly string BATCH_SQL_ID = "SELECT art_id from Art where art_index={1} limit 0,{0}";
        private static readonly string UPDATE_RECORD = "UPDATE art set art_index={1} where art_id={0}";
        
        public IndexArt()
        {
            config = new Configuration();
            config.AddAssembly("FutureOpen.Core");
            factory = config.BuildSessionFactory();
            writer = IndexManager.GetArtIndexWriter();
            reader = IndexManager.GetArtIndexReader();
        }

        public string GetC(object obj)
        {
            if (obj == null)
            {
                return string.Empty;
            }
            else
            {
                return obj.ToString();
            }
        }

        public void StartIndex()
        {
            bool result = true;
            while (result)
            {
                result = DoIndex(1000);                
            } 
        }

        
        public bool  DoIndex(int count)
        {

            bool hasRecord = true;
            string sql = string.Format(BATCH_SQL, count, IndexStatus.IndexType_New);
          
            SqlString selectString = new SqlString(sql);
            using (ISession session = factory.OpenSession())
            {
                ITransaction tran = session.BeginTransaction();
                IDbCommand cmd = factory.ConnectionProvider.Driver.GenerateCommand(System.Data.CommandType.Text, selectString, new NHibernate.SqlTypes.SqlType[] { });
                cmd.Connection = session.Connection;
                IDataReader rs = cmd.ExecuteReader();

                int n = 0;
                while (rs.Read())
                {
                    n++;
                    string id = GetC(rs[FieldNames.FIELD_ART_ID]);
                    string title = GetC(rs[FieldNames.FIELD_ART_TITLE]);
                    string content = GetC(rs[FieldNames.FIELD_ART_CONTENT]);
                    string type = GetC(rs[FieldNames.FIELD_ART_TYPE]);
                    string cat = GetC(rs[FieldNames.FIELD_ART_CAT]);
                    DateTime time = DateTime.Parse(GetC(rs[FieldNames.FIELD_ART_TIME]));
                    

                    //if (indexType == IndexStatus.IndexType_New)
                    {
                        Document doc = new Document();
                        doc.Add(new Field(FieldNames.FIELD_ART_ID, id, Field.Store.YES, Field.Index.UN_TOKENIZED));
                        doc.Add(new Field(FieldNames.FIELD_ART_TITLE, title, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
                        doc.Add(new Field(FieldNames.FIELD_ART_CONTENT, content, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
                        doc.Add(new Field(FieldNames.FIELD_ART_TYPE, type, Field.Store.YES, Field.Index.UN_TOKENIZED));
                        doc.Add(new Field(FieldNames.FIELD_ART_CAT, cat, Field.Store.YES, Field.Index.UN_TOKENIZED));
                        doc.Add(new Field(FieldNames.FIELD_ART_TIME,
                                DateTools.DateToString(time, DateTools.Resolution.HOUR), Field.Store.YES, Field.Index.UN_TOKENIZED));

                        writer.AddDocument(doc);
                                                
                        UpdateRecord(factory, session, tran, Int32.Parse(id), IndexStatus.IndexType_Indexed);
                    }

                    hasRecord = (n == 0);

                }
                tran.Commit();
            }
            return hasRecord;
         
        }


        public void Remove(int count)
        {

            string sql = string.Format(BATCH_SQL_ID, count, IndexStatus.IndexType_Updated);

            SqlString selectString = new SqlString(sql);
            using (ISession session = factory.OpenSession())
            {
                ITransaction tran = session.BeginTransaction();
                IDbCommand cmd = factory.ConnectionProvider.Driver.GenerateCommand(System.Data.CommandType.Text, selectString, new NHibernate.SqlTypes.SqlType[] { });
                cmd.Connection = session.Connection;
                IDataReader rs = cmd.ExecuteReader();

                while (rs.Read())
                {
                    string id = GetC(rs[FieldNames.FIELD_ART_ID]);
                    reader.DeleteDocuments(new Term(FieldNames.FIELD_ART_ID, id));
                    UpdateRecord(factory, session, tran, Int32.Parse(id), IndexStatus.IndexType_New);                    
                }
                tran.Commit();
            }

        }

        public void UpdateRecord(ISessionFactory factory, ISession session, ITransaction tran, int id, short status)
        {
            string sql = string.Format(UPDATE_RECORD, id, status);
            SqlString updateString = new SqlString(sql);
            IDbCommand cmd = factory.ConnectionProvider.Driver.GenerateCommand(System.Data.CommandType.Text, 
                updateString, new NHibernate.SqlTypes.SqlType[] { });
            cmd.Connection = session.Connection;
            cmd.ExecuteNonQuery();
        }
    }

}
